package com.lidy.tankbattle.tankgame1;

import com.lidy.tankbattle.tankgame1.constant.TankPriorities;
import com.lidy.tankbattle.tankutils.ThreadUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lidy
 * @version V1.0
 * @classname TankPanel1
 * @description 游戏操作界面
 * @date 2022/5/28 15:29
 */
public class TankPanel1 extends JPanel implements KeyListener, Runnable {

    /**
     * 己方坦克
     **/
    private Hero hero;

    /**
     * 己方坦克是否存活
    **/
    private Boolean myTankLive = true;

    /**
     * 敌方坦克
     **/
    private final ConcurrentHashMap<Integer, EnemyTank> enemyTanks = new ConcurrentHashMap<>(10);


    /**
     * 游戏是否进行中
    **/
    private Boolean gameContinue = true;

    private final int PANEL_WIDTH;

    private final int PANEL_HEIGHT;

    public TankPanel1(int panelWidth, int panelHeight) {
        PANEL_WIDTH = panelWidth;
        PANEL_HEIGHT = panelHeight;
    }

    /**
     * @author: lidy
     * @description: 添加面板内容
     * @date: 2022/6/2 9:55
     */
    public void addTanks(int initX, int initY, int initDirection) {
        hero = new Hero(initX, initY, initDirection, 1, TankPriorities.MY_TANK_INIT_BLOOD_VOLUME);
        for (int i = 0; i < TankPriorities.ENEMY_TANK_NUMBER; i++) {
            EnemyTank enemyTank = new EnemyTank(200 * i + 100, 0, TankPriorities.DIRECTION_DOWN, i + 2, TankPriorities.ENEMY_TANK_INIT_BLOOD_VOLUME, (int)(Math.random() * 100) + 10);
            enemyTanks.put(enemyTank.getNumber(), enemyTank);
            ThreadUtil.threadPoolExecutor.execute(enemyTank);
        }
    }

    /**
     * @author: lidy
     * @description: 面板画图区
     * @date: 2022/6/2 9:55
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);
        // 画自己的坦克
        drawTank(g, hero);
        // 画自己坦克的子弹
        drawBullets(g, hero.getBullets());
        // 画敌方坦克和子弹
        enemyTanks.forEach((number, enemyTank) -> {
            drawTank(g, enemyTank);
            drawBullets(g, enemyTank.getBullets());
        });
    }

    /**
     * @author: lidy
     * @description: 画子弹
     * @date: 2022/5/31 19:58
     */
    public void drawBullets(Graphics g, ConcurrentHashMap<Bullet, Integer> bullets) {
        bullets.forEach((bullet, i) -> {
            if (bullet.getLive()) {
                int width, length;
                switch (bullet.getDirection()) {
                    case TankPriorities.DIRECTION_UP, TankPriorities.DIRECTION_DOWN -> {
                        width = 2;
                        length = 5;
                    }
                    default -> {
                        width = 5;
                        length = 2;
                    }
                }
                g.fill3DRect(bullet.getX(), bullet.getY(), width, length, false);
            }
        });
    }

    /**
     * @author: lidy
     * @description: 画坦克
     * @date: 2022/5/28 15:57
     */
    public void drawTank(Graphics g, Tank tank) {
        if (!tank.getLive()) {
            return;
        }
        int x = tank.getX(), y = tank.getY(), direction = tank.getDirection(), type = tank.getType();
        switch (type) {
            // 我们的坦克
            case TankPriorities.MY_TANK_TYPE -> g.setColor(Color.cyan);
            // 敌人的坦克
            case TankPriorities.ENEMY_TANK_TYPE -> g.setColor(Color.yellow);
            default -> {
            }
        }

        switch (direction) {
            // 向上
            case TankPriorities.DIRECTION_UP -> {
                // 左边轮子
                g.fill3DRect(x, y, 10, 60, false);
                // 右边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);
                // 车厢
                g.fill3DRect(x + 10, y + 10, 20, 40, false);
                // 炮筒
                g.fill3DRect(x + 19, y, 2, 20, false);
                // 炮塔
                g.fillOval(x + 10, y + 20, 20, 20);
            }
            // 向下
            case TankPriorities.DIRECTION_DOWN -> {
                // 左边轮子
                g.fill3DRect(x, y, 10, 60, false);
                // 右边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);
                // 车厢
                g.fill3DRect(x + 10, y + 10, 20, 40, false);
                // 炮筒
                g.fill3DRect(x + 19, y + 40, 2, 20,false);
                // 炮塔
                g.fillOval(x + 10, y + 20, 20, 20);
            }
            // 向左
            case TankPriorities.DIRECTION_LEFT -> {
                // 上边轮子
                g.fill3DRect(x, y, 60, 10, false);
                // 下边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);
                // 车厢
                g.fill3DRect(x + 10, y + 10, 40, 20, false);
                // 炮筒
                g.fill3DRect(x, y + 19, 20, 2, false);
                // 炮塔
                g.fillOval(x + 20, y + 10, 20, 20);
            }
            // 向右
            case TankPriorities.DIRECTION_RIGHT -> {
                // 上边轮子
                g.fill3DRect(x, y, 60, 10, false);
                // 下边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);
                // 车厢
                g.fill3DRect(x + 10, y + 10, 40, 20, false);
                // 炮筒
                g.fill3DRect(x + 40, y + 19, 20, 2, false);
                // 炮塔
                g.fillOval(x + 20, y + 10, 20, 20);
            }
            default -> {
            }
        }
    }

    /**
     * @author: lidy
     * @description: 有字符输出时，该方法会触发
     * @date: 2022/6/2 9:56
     */
    @Override
    public void keyTyped(KeyEvent e) {

    }

    /**
     * @author: lidy
     * @description: 当某个键按下时，该方法会触发
     * @date: 2022/6/2 9:56
     */
    @Override
    public void keyPressed(KeyEvent e) {
        // 根据按下的不同键，来处理小球的移动（上下左右移动）
        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            heroTankMove(TankPriorities.DIRECTION_DOWN);
        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
            heroTankMove(TankPriorities.DIRECTION_UP);
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            heroTankMove(TankPriorities.DIRECTION_LEFT);
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            heroTankMove(TankPriorities.DIRECTION_RIGHT);
        }
        // 按下Q键发射子弹
        if (e.getKeyCode() == KeyEvent.VK_Q) {
            if (hero.getLive()) {
                hero.shot();
            }
        }
    }

    /**
     * @author: lidy
     * @description: 己方坦克移动
     * @date: 2022/6/2 9:56
     */
    private void heroTankMove(int destDirection) {
        hero.setDirection(destDirection);
        switch (destDirection) {
            case TankPriorities.DIRECTION_UP:
                if (hero.getY() > 0) {
                    hero.moveUp();
                }
                break;
            case TankPriorities.DIRECTION_DOWN:
                if (hero.getY() < PANEL_HEIGHT) {
                    hero.moveDown();
                }
                break;
            case TankPriorities.DIRECTION_LEFT:
                if (hero.getX() > 0) {
                    hero.moveLeft();
                }
                break;
            case TankPriorities.DIRECTION_RIGHT:
                if (hero.getX() < PANEL_WIDTH) {
                    hero.moveRight();
                }
                break;
            default:
                break;
        }
        this.repaint();
    }

    /**
     * @author: lidy
     * @description: 改变方向时转向，不移动
     * @date: 2022/6/1 16:57
     */
    private void heroTankMoveDirection(int destDirection) {
        int currentDirection = hero.getDirection();
        // 目标方向和当前方向相同就是移动
        if (currentDirection == destDirection) {
            switch (destDirection) {
                case TankPriorities.DIRECTION_UP:
                    if (hero.getY() > 0) {
                        hero.moveUp();
                        this.repaint();
                    }
                    break;
                case TankPriorities.DIRECTION_DOWN:
                    if (hero.getY() < PANEL_HEIGHT) {
                        hero.moveDown();
                        this.repaint();
                    }
                    break;
                case TankPriorities.DIRECTION_LEFT:
                    if (hero.getX() > 0) {
                        hero.moveLeft();
                        this.repaint();
                    }
                    break;
                case TankPriorities.DIRECTION_RIGHT:
                    if (hero.getX() < PANEL_WIDTH) {
                        hero.moveRight();
                        this.repaint();
                    }
                    break;
                default:
                    break;
            }
        } else { // 目标方向和当前方向不同是转向
            if (currentDirection == TankPriorities.DIRECTION_UP || currentDirection == TankPriorities.DIRECTION_DOWN) {
                if (destDirection == TankPriorities.DIRECTION_LEFT || destDirection == TankPriorities.DIRECTION_RIGHT) {
                    hero.setX(hero.getX() - 10);
                    hero.setY(hero.getY() + 10);
                }
            } else if (currentDirection == TankPriorities.DIRECTION_LEFT || currentDirection == TankPriorities.DIRECTION_RIGHT) {
                if (destDirection == TankPriorities.DIRECTION_UP || destDirection == TankPriorities.DIRECTION_DOWN) {
                    hero.setX(hero.getX() + 10);
                    hero.setY(hero.getY() - 10);
                }
            }
            hero.setDirection(destDirection);
            this.repaint();
        }
    }

    /**
     * @author: lidy
     * @description: 当某个键放开时，该方法会触发
     * @date: 2022/6/2 9:56
     */
    @Override
    public void keyReleased(KeyEvent e) {

    }

    /**
     * @author: lidy
     * @description: 子弹是否击中坦克判断
     * @date: 2022/6/2 9:58
     */
    private void bulletHitTank(Bullet bullet, Tank tank) {
        if (bullet.getLive() && tank.getLive() && bullet.getFromTankNumber() != tank.getNumber()) {
            int tankLeftX = tank.getX(), tankUpY = tank.getY(), tankRightX, tankDownY;
            switch (tank.getDirection()) {
                case TankPriorities.DIRECTION_UP, TankPriorities.DIRECTION_DOWN -> {
                    tankRightX = tankLeftX + TankPriorities.TANK_WIDTH;
                    tankDownY = tankUpY + TankPriorities.TANK_HEIGHT;
                }
                default -> {
                    tankRightX = tankLeftX + TankPriorities.TANK_HEIGHT;
                    tankDownY = tankUpY + TankPriorities.TANK_WIDTH;
                }
            }
            if (bullet.getX() > tankLeftX && bullet.getX() < tankRightX && bullet.getY() > tankUpY && bullet.getY() < tankDownY) {
                bullet.setLive(false);
                tank.setBloodVolume(tank.getBloodVolume() - bullet.getPower());
                if (tank.getBloodVolume() <= 0) {
                    tank.setLive(false);
                }
            }
        }
    }

    /**
     * @author: lidy
     * @description: 200mm重绘一次面板
     * @date: 2022/6/1 16:57
     */
    @Override
    public void run() {
        while (gameContinue) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            enemyTanks.forEach((number, enemyTank) -> {
                if (enemyTank.getLive()) {
                    enemyTank.getBullets().forEach((bullet, fromTankNumber) -> {
                        if (bullet.getLive()) {
                            bulletHitTank(bullet, hero);
                            if (myTankLive && !hero.getLive()) {
                                System.out.println("己方坦克消亡...");
                                // TODO 己方坦克死亡退出游戏
                                myTankLive = false;
                                // gameContinue = false;
                            }
                        } else {
                            enemyTank.getBullets().remove(bullet);
                        }
                    });
                }
            });
            hero.getBullets().forEach((bullet, fromTankNumber) -> {
                enemyTanks.forEach((number, tank) -> {
                    bulletHitTank(bullet, tank);
                    if (!tank.getLive()) {
                        enemyTanks.remove(number);
                    }
                });
            });
            this.repaint();
        }
    }


}
